#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <functional>
#include <unordered_map>
#include <fstream>
#include "Log.hpp"

using namespace log_ns;

const static std::string base_sep = "\r\n";
const static std::string line_sep = ": ";
const static std::string prefix_path = "wwwroot"; // web 根目录
const static std::string homepage = "index.html";

const static std::string http_version = "HTTP/1.0";
const static std::string space_sep = " ";

const static std::string suffix_sep = ".";

const static std::string html_404 = "404.html";

const static std::string arg_sep = "?";



class HttpRequest
{
private:
    std::string GetLine(std::string &reqstr)
    {
        auto pos = reqstr.find(base_sep);
        if (pos == std::string::npos)
            return "";
        std::string line = reqstr.substr(0, pos);
        reqstr.erase(0, line.size() + base_sep.size());
        return line.empty() ? base_sep : line;
    }

    void ParseReqLine()
    {
        std::stringstream ss(_req_line); // 有点像 cin
        // cin >> _method >> _url >> _version;
        ss >> _method >> _url >> _version;

        if (strcasecmp(_method.c_str(), "GET") == 0)
        {
            auto pos = _url.find(arg_sep);
            if (pos != std::string::npos)
            {
                // 包含问号，带参
                _req_body_text = _url.substr(pos + arg_sep.size());
                _url.resize(pos);
            }
        }

        _path += _url;
        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        auto pos = _path.rfind(suffix_sep);
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }

    void ParseReqHeader()
    {
        for (auto &header : _req_headers)
        {
            auto pos = header.find(line_sep);
            if (pos == std::string::npos)
                continue;
            std::string key = header.substr(0, pos);
            std::string value = header.substr(pos + line_sep.size());
            if (key.empty() || value.empty())
                continue;
            _headers_kv.insert(std::make_pair(key, value));
        }
    }

public:
    HttpRequest()
        : _blank_line(base_sep), _path(prefix_path)
    {
    }

    void Deserialize(std::string &reqstr)
    {
        // 基本的反序列化
        _req_line = GetLine(reqstr);

        std::string header;
        do
        {
            header = GetLine(reqstr);
            if (header.empty())
                break;
            else if (header == base_sep)
                break;
            _req_headers.push_back(header);
        } while (true);

        if (!reqstr.empty())
        {
            _req_body_text = reqstr;
        }

        // 再进一步反序列化
        ParseReqLine();
        ParseReqHeader();
    }

    std::string GetUrl()
    {
        LOG(DEBUG, "Client want url -> %s\n", _url.c_str());
        return _url;
    }

    std::string GetPath()
    {
        LOG(DEBUG, "Client want path -> %s\n", _path.c_str());
        return _path;
    }

    std::string GetSuffix()
    {
        return _suffix;
    }

    std::string Method()
    {
        LOG(DEBUG, "HTTP Request Method: %s\n", _method.c_str());
        return _method;
    }

    std::string GetResultBody()
    {
        LOG(DEBUG, "HTTP Request Method: %s, args: %s, path: %s\n", _method.c_str(), _req_body_text.c_str(), _path.c_str());
        return _req_body_text;
    }

    void Print()
    {
        std::cout << "-------------------------------------------" << std::endl;
        std::cout << "###" << _req_line << std::endl;
        for (auto &header : _req_headers)
        {
            std::cout << "@@@" << header << std::endl;
        }
        std::cout << "***" << _blank_line;
        std::cout << ">>>" << _req_body_text << std::endl;

        std::cout << "Method: " << _method << std::endl;
        std::cout << "URL: " << _url << std::endl;
        std::cout << "Version: " << _version << std::endl;

        for (auto &head_kv : _headers_kv)
        {
            std::cout << "$$$" << head_kv.first << " -> " << head_kv.second << std::endl;
        }
    }

    ~HttpRequest()
    {
    }

private:
    // 基本的 http 请求格式
    std::string _req_line;                 // 请求行
    std::vector<std::string> _req_headers; // 请求报头
    std::string _blank_line;               // 空行
    std::string _req_body_text;            // 请求正文

    // 更具体的属性字段
    std::string _method;
    std::string _url;
    std::string _path;
    std::string _suffix; // 表明请求的资源后缀
    std::string _version;
    std::unordered_map<std::string, std::string> _headers_kv;
};

class HttpResponse
{
private:
public:
    HttpResponse()
        : _version(http_version), _blank_line(base_sep)
    {
    }

    void AddCode(int code, const std::string &desc)
    {
        _status_code = code;
        _desc = desc;
    }

    void AddHandler(const std::string &k, const std::string &v)
    {
        _headers_kv[k] = v;
    }

    void AddBodyText(const std::string body_text)
    {
        _resp_body_text = body_text;
    }

    std::string Serialize()
    {
        // 构建状态行
        _stat_line = _version + space_sep + std::to_string(_status_code) + space_sep + _desc + base_sep;

        // 构建响应报头
        for (auto &header : _headers_kv)
        {
            std::string header_line = header.first + line_sep + header.second + base_sep;
            _resp_headers.push_back(header_line);
        }

        // 空行和正文（已完成）

        // 开始序列化
        std::string respstr = _stat_line;
        for (auto &line : _resp_headers)
        {
            respstr += line;
        }
        respstr += (_blank_line + _resp_body_text);

        return respstr;
    }

    ~HttpResponse()
    {
    }

private:
    // http response 基本属性
    std::string _version;
    int _status_code;
    std::string _desc;
    std::unordered_map<std::string, std::string> _headers_kv;

    // 基本的 http 响应格式
    std::string _stat_line;                 // 状态行
    std::vector<std::string> _resp_headers; // 响应报头
    std::string _blank_line;                // 空行
    std::string _resp_body_text;            // 响应正文

    // 更具体的属性字段
};

using func_t = std::function<HttpResponse(HttpRequest&)>;

class HttpServer
{
private:
    std::string GetFileContent(const std::string path)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return "";

        in.seekg(0, in.end);
        int filesize = in.tellg(); // 告知 rw 的偏移量是多少
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);

        in.close();
        return content;
    }

public:
    HttpServer()
    {
        _mini_type.insert(std::make_pair(".html", "text/html"));
        _mini_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mini_type.insert(std::make_pair(".png", "image/png"));
        _mini_type.insert(std::make_pair(".default", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
        _code_to_desc.insert(std::make_pair(403, "Forbidden"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
    }

    // #define TEST
    std::string HandlerHttpRequest(std::string &reqstr)
    {
#ifdef TEST
        std::cout << "------------------------------" << std::endl;
        std::cout << reqstr << std::endl;

        std::string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n\r\n";
        responsestr += "<html><h1>Hello Linux! Hello What!</h1></html>";

        return responsestr;
#else
        std::cout << "------------------------------" << std::endl;
        std::cout << reqstr << std::endl;

        HttpRequest req;
        HttpResponse resp;
        req.Deserialize(reqstr);
        // req.Method();
        // req.GetResultBody();

        if (req.GetPath() == "wwwroot/redir")
        {
            // 进行重定向 
            std::string redir_path = "https://www.qq.com";
            resp.AddCode(301, _code_to_desc[301]);
            resp.AddHandler("Location", redir_path);
        }
        else if (!req.GetResultBody().empty())
        {
            if (IsEmptyExists(req.GetPath()))
            {
                resp = _service_list[req.GetPath()](req);
            }
        }
        else
        {
            // 处理静态资源 
            std::string content = GetFileContent(req.GetPath());
            if (content.empty())
            {
                content = GetFileContent("wwwroot/404.html");
                resp.AddCode(404, _code_to_desc[404]);
                resp.AddHandler("Content-Length", std::to_string(content.size()));
                resp.AddHandler("Content-Type", _mini_type[".html"]);
                resp.AddBodyText(content);
            }
            else
            {
                resp.AddCode(200, _code_to_desc[200]);
                resp.AddHandler("Content-Length", std::to_string(content.size()));
                resp.AddHandler("Content-Type", _mini_type[req.GetSuffix()]);
                resp.AddHandler("Set-Cookie", "username=xixi");
                // resp.AddHandler("Set-Cookie:", "userpwd=123456");
                resp.AddBodyText(content);
            }
        }
        return resp.Serialize();

#endif
    }

    void InsertService(const std::string& servicename, func_t service)
    {
        std::string s = prefix_path + servicename;
        _service_list[s] = service;
    }

    bool IsEmptyExists(const std::string& servicename)
    {
        auto iter = _service_list.find(servicename);
        if (iter == _service_list.end()) return false;
        else return true;
    }

    ~HttpServer()
    {
    }

private:
    std::unordered_map<std::string, std::string> _mini_type;
    std::unordered_map<int, std::string> _code_to_desc;

    std::unordered_map<std::string, func_t> _service_list;
};
